from math import floor
from app.commons import is_isbn_or_key
from app.models.drift import Drift
from app.models.gift import Gift
from app.models.wish import Wish
from app.spider.yushu_book import YuShuBook
from .base import db, Base
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
from app import login_manager
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from flask import current_app


class User(UserMixin, Base):
    __searchable__ = ['nickname', 'email']

    id = db.Column(db.Integer, primary_key=True)
    nickname = db.Column(db.String(24), nullable=False)
    _password = db.Column('password', db.String(128))
    phone_number = db.Column(db.String(18), unique=True)
    email = db.Column(db.String(50), unique=True, nullable=False)
    confirmed = db.Column(db.Boolean, default=False)
    beans = db.Column(db.Float, default=0)
    send_counter = db.Column(db.Integer, default=0)
    receive_counter = db.Column(db.Integer, default=0)

    @property
    def password(self):
        return self._password

    @password.setter
    def password(self, raw):
        # 当前函数会在被赋值的时候调用.
        self._password = generate_password_hash(raw)

    def check_password(self, raw):
        return check_password_hash(self._password, raw)

    def can_save_to_list(self, isbn):
        # 验证是否是isbn编号
        if is_isbn_or_key(isbn) != 'isbn':
            return False
        yushu_book = YuShuBook()
        yushu_book.search_by_isbn(isbn)
        # 验证书籍是否存在
        if not yushu_book.first:
            return False

        # 这本书不能在还没赠送出去的时候,继续赠送.(我有没有赠送过这本书,赠送过不能添加到清单)
        gift = Gift.query.filter_by(uid=self.id, isbn=isbn, launched=False).first()
        # 这本书不能在自己的心愿清单中.(我有没有收藏过这本书,收藏过不能再次收藏)
        wish = Wish.query.filter_by(uid=self.id, isbn=isbn, launched=False).first()
        # 都没有的情况下可以添加
        if not gift and not wish:
            return True
        else:
            return False

    def generate_token(self, expiration=600):
        s = Serializer(current_app.config['SECRET_KEY'], expiration) # 生成加密的序列化对象.
        return s.dumps({'id': self.id}).decode('utf-8')

    @staticmethod
    def reset_password(token, new_password):
        s = Serializer(current_app.config['SECRET_KEY'])  # 生成序列化器对象
        try:
            data = s.loads(token.encode('utf-8')) # 解密失败会抛出异常
        except Exception as e:
            return False
        uid = data.get('id')
        with db.auto_commit():
            user = User.query.get(uid)
            user.password = new_password
        return True

    def can_send_drift(self):
        # 是否有足够的钱
        if self.beans < 1:
            return False
        # 送出过多少书籍
        send_gift_count = Gift.query.filter_by(uid=self.id, launched=True).count()
        # 收到过多少书籍
        receice_gift_count = Drift.query.filter_by(requester_id=self.id, pending=2).count()
        # 获得2本书后,必须赠送1本,才能继续索取
        return True if floor(receice_gift_count / 2) <= floor(send_gift_count) else False

    @property
    def summary(self):
        return dict(
            nickname=self.nickname,
            beans=self.beans,
            email=self.email,
            send_receive=str(self.send_counter) + '/' + str(self.receive_counter) # 赠送/接受
        )


# 让login模块调用,获取User对象.
@login_manager.user_loader
def get_user(uid):
    return User.query.get(uid)